package cn.com.bluemoon.daps.model.service.impl;

import cn.com.bluemoon.daps.common.constant.DapConstant;
import cn.com.bluemoon.daps.common.enums.BmStatus;
import cn.com.bluemoon.daps.common.toolkit.BmAssetUtils;
import cn.com.bluemoon.daps.model.entity.DapDataModelUserAccredit;
import cn.com.bluemoon.daps.model.mapper.DapDataModelUserAccreditMapper;
import cn.com.bluemoon.daps.model.service.DapDataModelService;
import cn.com.bluemoon.daps.model.service.DapDataModelUserAccreditService;
import cn.com.bluemoon.daps.system.dto.SystemUserDto;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import lombok.Getter;
import lombok.Setter;
import lombok.ToString;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.io.Serializable;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.Set;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.stream.Collectors;

/**
 * <p>
 * 模型用户授权表 服务实现类
 * </p>
 *
 * @author admin
 * @since 2021-02-22
 */
@Slf4j
@Service
public class DapDataModelUserAccreditServiceImpl extends ServiceImpl<DapDataModelUserAccreditMapper, DapDataModelUserAccredit>
        implements DapDataModelUserAccreditService {


    @Autowired
    private DapSystemModuleFacade systemModuleFacade;

    @Resource
    private DapDataModelService modelService;

    /**
     * <important>只处理模型管理者的更新</important>
     * <p>
     * 增加模型的创建人和模型管理者（新增中写入创建者+模型管理者、编辑中创建者不变+调整模型管理者）
     * 存在模型管理者就是创建者
     *
     * @param modelId      模id
     * @param modelManager 管理者账号
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public void changUserAccreditByModelSaveOrUpdate(String modelId, String modelManager) {
        // 检查模型id、账号
        modelService.getByIdAsset(modelId, "模型已删除");
        BmAssetUtils.notNull(modelManager, "模型管理者不可为空！！");

        Map<String, SystemUserDto> userAccountAndPojo = getStringSystemUserDtoMap();
        SystemUserDto systemUserDto = userAccountAndPojo.getOrDefault(modelManager, null);
        BmAssetUtils.notNull(systemUserDto, "模型管理员账号无效！！");
        // 先删除模型下的历史管理者，然后再新增
        LambdaUpdateWrapper<DapDataModelUserAccredit> updateModelManger = bmLambdaUpdate().eq(DapDataModelUserAccredit::getModelId, modelId)
                .eq(DapDataModelUserAccredit::getModelManager, Boolean.TRUE).set(DapDataModelUserAccredit::getModelManager, Boolean.FALSE);
        boolean removeU = update(updateModelManger);
        // 若模型下的非模型管理者为新增的模型管理员，则更新为模型管理者，若没有对应用
        LambdaQueryWrapper<DapDataModelUserAccredit> exitNotManagerUser = bmLambdaQuery().eq(DapDataModelUserAccredit::getModelId, modelId)
                .eq(DapDataModelUserAccredit::getModelManager, Boolean.FALSE).eq(DapDataModelUserAccredit::getUserAccount, modelManager);
        DapDataModelUserAccredit userAccredit = Optional.ofNullable(getOne(exitNotManagerUser)).map(d -> {
            d.setModelManager(Boolean.TRUE);
            return d;
        }).orElseGet(() -> sysUserDto2UserAccreditByModelId(modelId, systemUserDto, true));
        boolean save = saveOrUpdate(userAccredit);
        log.info("清除模型id={}历史的管理者，情况：{}", modelId, (removeU ? "首次创建不存在历史模型管理者:" : "编辑模型管理:") + save);
    }

    /**
     * <important>只处理非模型管理者的更新</important>
     * <p>
     * 更新模型授权信息（不可删除模型管理者，若要删除使用{@link DapDataModelUserAccreditServiceImpl#addUsersByModelSaveOrUpdate(java.lang.String, java.lang.String)}）
     *
     * @param modelId  模型id
     * @param accounts 账号
     * @return 结果
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean upsertAccredit(String modelId, List<String> accounts) {
        // 检查模型id
        modelService.getByIdAsset(modelId, "模型已删除");
        // 判断账号是否有效
        Map<String, SystemUserDto> userAccountAndPojo = getStringSystemUserDtoMap();
        // 增加判断新增授权账号是本身就是模型管理员的处理（是，直接把普通的用户过滤掉，否，忽略）--找出模型id下的模型管理员去掉
        LambdaQueryWrapper<DapDataModelUserAccredit> findModelManager = bmLambdaQuery().eq(DapDataModelUserAccredit::getModelId, modelId).eq(DapDataModelUserAccredit::getModelManager, Boolean.TRUE);
        Set<String> managers = list(findModelManager).stream().map(DapDataModelUserAccredit::getUserAccount).collect(Collectors.toSet());
        List<String> outOfManagerAccounts = accounts.stream().filter(d -> {
            if (managers.contains(d)) {
                log.warn("模型id={}本接口不对模型管理员{}进行操作！！，已被过滤", modelId, d);
            }
            return !managers.contains(d);
        }).collect(Collectors.toList());
        // 构造结果集
        AtomicBoolean noValidAccount = new AtomicBoolean(false);
        Set<SystemUserDto> systemUserDtos = outOfManagerAccounts.stream()
                .map(a -> userAccountAndPojo.getOrDefault(a, null))
                .peek(d -> {
                    if (d == null && !noValidAccount.get()) {
                        noValidAccount.set(true);
                    }
                })
                .collect(Collectors.toSet());
        BmAssetUtils.isFalse(noValidAccount.get(), "存在无效账号！！");
        // 先删除（不可删除模型管理者），后新增
        LambdaQueryWrapper<DapDataModelUserAccredit> eq = bmLambdaQuery().eq(DapDataModelUserAccredit::getModelId, modelId)
                .eq(DapDataModelUserAccredit::getModelManager, Boolean.FALSE);
        boolean remove = remove(eq);
        log.info("清除模型历史授权信息, status:{}", remove);
        List<DapDataModelUserAccredit> accredits = systemUserDtos.stream()
                .map(d -> sysUserDto2UserAccreditByModelId(modelId, d, false)).collect(Collectors.toList());
        boolean saveBatch = bmSaveBatch(accredits);
        log.info("model={},模型授权信息完成，status:{}", modelId, saveBatch);
        return saveBatch;
    }

    private Map<String, SystemUserDto> getStringSystemUserDtoMap() {
        return systemModuleFacade.systemUserList().stream().collect(Collectors.toMap(SystemUserDto::getAccount, d -> d, (a, b) -> b));
    }

    /**
     * 转换器
     *
     * @param modelId        模型id
     * @param d              源
     * @param isModelManager true 管理者 false不是
     * @return 结果
     */
    private DapDataModelUserAccredit sysUserDto2UserAccreditByModelId(String modelId, SystemUserDto d,
                                                                      boolean isModelManager) {
        DapDataModelUserAccredit accredit = new DapDataModelUserAccredit();
        accredit.setModelId(modelId);
        accredit.setUserAccount(d.getAccount());
        accredit.setUserEmail(d.getEmail());
        accredit.setOperType(9);
        accredit.setModelManager(isModelManager);
        return accredit;
    }

    /**
     * 获取用户信息+是否已选择
     *
     * @param modelId 模型id
     * @return x
     */
    @Override
    public List<ModelUserAccreditVo> queryUserDtos(String modelId) {
        // 检查模型id
        modelService.getByIdAsset(modelId, "模型已删除");
        LambdaQueryWrapper<DapDataModelUserAccredit> eq = bmLambdaQuery().eq(DapDataModelUserAccredit::getModelId, modelId);
        List<DapDataModelUserAccredit> modelUserSelected = list(eq);
        Map<String, DapDataModelUserAccredit> accountAndPojo = modelUserSelected.stream()
                .collect(Collectors.toMap(DapDataModelUserAccredit::getUserAccount, d -> d, (a, b) -> b));
        List<SystemUserDto> list = systemModuleFacade.systemUserList();
        List<ModelUserAccreditVo> modelUserAccreditVos = list.stream().map(ModelUserAccreditVo::new)
                .filter(d -> d.getUserDto() != null)
                .peek(d -> {
                    DapDataModelUserAccredit accredit = accountAndPojo.get(d.getUserDto().getAccount());
                    if (accredit != null) {
                        d.setChosen(true);
                        d.setModelManager(accredit.getModelManager());
                    }
                })
                .collect(Collectors.toList());
        return modelUserAccreditVos;
    }

    /**
     * 删除模型
     *
     * @param isLogic 是否逻辑
     * @param modelId 模型id
     */
    @Override
    public void deleteByModelId(boolean isLogic, String modelId) {
        boolean status;
        if (isLogic) {
            LambdaUpdateWrapper<DapDataModelUserAccredit> del = bmLambdaUpdate().eq(DapDataModelUserAccredit::getModelId, modelId)
                    .set(DapDataModelUserAccredit::getBmStatus, BmStatus.DELETE);
            status = update(del);
        } else {
            LambdaQueryWrapper<DapDataModelUserAccredit> del = bmLambdaQuery().eq(DapDataModelUserAccredit::getModelId, modelId);
            status = remove(del);
        }
        log.info("{}删除模型id={}下的用户授权信息：{}", (isLogic ? "逻辑" : "物理"), modelId, status);
    }

    @Override
    public void saveCreateBy(String modelId, String createBy) {
        // 检查模型id
        modelService.getByIdAsset(modelId, "模型已删除");
        DapDataModelUserAccredit accredit = new DapDataModelUserAccredit();
        accredit.setModelId(modelId);
        accredit.setModelManager(false);
        accredit.setUserAccount(createBy);
        accredit.setUserEmail(DapConstant.formatEmail(createBy, true));
        accredit.setOperType(9);
        boolean save = save(accredit);
        log.info("创建人{}，授予模型{}权限，status:{}", createBy, modelId, save);
    }

    @Getter
    @ToString
    @Setter
    public static class ModelUserAccreditVo implements Serializable {

        private static final long serialVersionUID = 1L;

        private SystemUserDto userDto;

        private Boolean chosen = Boolean.FALSE;

        private Boolean modelManager = Boolean.FALSE;

        public ModelUserAccreditVo() {
        }

        public ModelUserAccreditVo(SystemUserDto userDto) {
            this.userDto = userDto;
        }

        public ModelUserAccreditVo(SystemUserDto userDto, Boolean chosen) {
            this.userDto = userDto;
            this.chosen = chosen;
        }
    }

}
